package tp_sd_base;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import java.io.EOFException;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.StreamCorruptedException;
import java.io.UTFDataFormatException;
import java.net.Socket;
import java.util.List;

/**
 *
 * @author kill9
 */
public class ClientSocketChat {

    protected Socket socket;
    protected IClient client;
    protected String nickName;
    
    protected ObjectInputStream inputStream;
    protected ObjectOutputStream outputStream;

    public ClientSocketChat(Socket socket, IClient client) {
        this.socket = socket;
        this.client = client;
        try {
            outputStream = new ObjectOutputStream(socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    public void close() throws IOException {
        if (!socket.isClosed()) {
            socket.close();
        }
    }

    public boolean isClosed() {
        return socket.isClosed();
    }

    public void readMessage() throws IOException, ClassNotFoundException {

        int value = 0;
        try {
            if (inputStream == null) {
                inputStream = new ObjectInputStream(socket.getInputStream());
            }
            value = inputStream.readInt();

            switch (getMessageType(value)) {
                case ERROR:
                    client.onError(getErrorType(inputStream.readInt()), inputStream.readUTF());
                    break;
               case LOGIN:
               case REGISTRATION:
                    client.onLogin(inputStream.readUTF());
                    initValues();  // Inicializa valores
                    break;
                case LOGOUT:
                    client.onLogOut();
                    break;
                case MESSAGE:
                    client.onMessage(inputStream.readUTF(), inputStream.readUTF());
                    break;
                case RANKING:
                    client.onRanking(inputStream.readInt(), (List<Set<String,Integer>>) inputStream.readObject());
                    break;
                case REFRESH:
                    int i = inputStream.readInt();
                    List<String> list = (List<String>)inputStream.readObject();
                    client.onRefresh(i, list);
                    break;
                case PARTIAL_REFRESH : client.onPartialRefresh(inputStream.readInt(), inputStream.readInt(),(List<String>)inputStream.readObject());
                break;
                default:
                    client.onInvalidOperation(value);
            }
        } catch (ArrayIndexOutOfBoundsException ex) { // Cosiderar os códigos de erro como operação inválida
            client.onInvalidOperation(value);
        } catch (UTFDataFormatException ex) {
            client.onInvalidArgs();
        } catch (EOFException ex) {
            client.onInvalidArgs();
        } catch (ClassNotFoundException ex) {
            client.onInvalidArgs();
        } catch (InvalidClassException ex) {
            client.onInvalidArgs();
        } catch (StreamCorruptedException ex) {
            client.onInvalidArgs();
        } catch (OptionalDataException ex) {
            client.onInvalidArgs();
        } catch (ClassCastException ex) {
            client.onInvalidArgs();
        } catch (IOException ex) {
            client.onInvalidArgs();
        }
    }

    public void initValues() throws IOException {
        sendMessage(IServer.MESSAGE_TYPE.REFRESH.ordinal(), IServer.REFRESH_TYPE.ONLINE.ordinal(), null, null, null);
        sendMessage(IServer.MESSAGE_TYPE.REFRESH.ordinal(), IServer.REFRESH_TYPE.FOLLOWERS.ordinal(),null,null,null);
        sendMessage(IServer.MESSAGE_TYPE.REFRESH.ordinal(), IServer.REFRESH_TYPE.FOLLOWED.ordinal(),null,null,null);
    }

    public synchronized void sendMessage(int type, Integer type1, Integer type2, String st, Object object) throws IOException {
        outputStream.writeInt(type);
        if (type1 != null) {
            outputStream.writeInt(type1);
        }
        if (st != null) {
            outputStream.writeUTF(st);
        }
        if (type2 != null) {
            outputStream.writeInt(type2);
        }
        if (object != null) {
            outputStream.writeObject(object);
        }
        outputStream.flush();
    }

    public void sendMessage(IServer.MESSAGE_TYPE message_type, String msg) throws IOException {
        sendMessage(message_type.ordinal(), null, null, msg, null);
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getNickName() {
        return nickName;
    }

    protected static IServer.MESSAGE_TYPE getMessageType(int bs) {
        return IServer.MESSAGE_TYPE.values()[bs];
    }

    protected static IServer.ERROR_TYPE getErrorType(int bs) {
        return IServer.ERROR_TYPE.values()[bs];
    }

    protected static IServer.REFRESH_TYPE getRefreshType(int bs) {
        return IServer.REFRESH_TYPE.values()[bs];
    }

    public ObjectOutputStream getOutputStream() {
        return outputStream;
    }    
}
